function Vue(options) {
  // this --->  vm
  let _data = (this.$data = options.data);
  /*
    数据代理：
        将data里的数据，放到vm上，放到vm上为了我们在组件中获取的时候，直接通过this.xxx获取数据
        内部使用的是Object.defineproperty实现的代理
         Object.keys(_data)  ['msg','user']
  */
  Object.keys(_data).forEach((key) => {
    this.proxy(key);
  });
  /*
    数据劫持：
      将data里数据变成响应式的(get/set)，我们获取数据的时候，会触发get方法，在get方法里可以进行依赖收集
        修改数据的时候，会触发set方法，在set方法里或触发依赖更新
        它会通过递归调用，实现深层次数据劫持。
  */
  observe(_data);
}
// 数据代理
Vue.prototype.proxy = function (key) {
  Object.defineProperty(this, key, {
    get() {
      return this.$data[key];
    },
    set(newVal) {
      this.$data[key] = newVal;
    },
  });
};

// 数据劫持
function observe(data) {
  if (typeof data === "string") return;
  Object.keys(data).forEach((key) => {
    let originVal = data[key];
    // 递归调用数据劫持函数，进行深层次的数据劫持
    observe(originVal);
    Object.defineProperty(data, key, {
      get() {
        // 收集依赖
        return originVal;
      },
      set(newVal) {
        originVal = newVal;
        // 触发依赖更新
      },
    });
  });
}
